package com.ktgj.common.core.utils.xml;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.*;
import com.ktgj.common.core.utils.helper.ObjectHelper;
import com.ktgj.common.core.utils.helper.ReflectHelper;
import com.ktgj.common.core.utils.helper.StringHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class XmlHelp
{
	private final static Logger LOGGER = LoggerFactory.getLogger(XmlHelp.class);

	
	public static <T> List<T> getList(XElement ele, Class<?> clazz)
	{
		List<T> result = new ArrayList<T>();
		for (XElement v : ele.elements())
		{
			result.add(getData(v, false, clazz));
		}

		return result;
	}

	public static <T> T getData(XElement ele, Class<?> clazz)
	{
		return getData(ele, false, clazz);
	}

	@SuppressWarnings("unchecked")
	public static <T> T getData(XElement ele, boolean noListInfo, Class<?> clazz)
	{
		List<XmlPropertyData> lstProperties = ReflectHelper.getXmlProperties(clazz);

		Object result = null;
		try
		{
			result = clazz.newInstance();
		}
		catch (Exception e)
		{
			LOGGER.error(e.getMessage());
		}

		// 基本属性
		for (XAttribute attr : ele.attributes())
		{
			String attrName = attr.getName();
			XmlPropertyData pInfo = lstProperties.stream().filter(x -> x.attrName().equalsIgnoreCase(attrName)).findFirst().orElse(null);
			if (pInfo != null)
			{
				try
				{
					ReflectHelper.setValue(result, pInfo.attrName(), attr.getValue());
				}
				catch (Exception e)
				{
					LOGGER.error(e + "\t" + clazz.getName() + "\t" + ele.toString(), e);
				}
			}
		}

		if (noListInfo)
		{
			return (T) result;
		}

		// 列表
		for (XmlPropertyData v : lstProperties.stream().filter(x -> !StringHelper.isNullOrWhiteSpace(x.path())).collect(Collectors.toList()))
		{
			Field field = null;
			try
			{
				field = ReflectHelper.getField(clazz, v.propertyName());
			}
			catch (Exception e)
			{
				LOGGER.error(e.getMessage());
			}

			Object value = null;
			if (ParameterizedType.class.isAssignableFrom(field.getGenericType().getClass()))
			{
				ParameterizedType t = (ParameterizedType) field.getGenericType();
				Class<?> type = (Class<?>) t.getActualTypeArguments()[0];
				List<Object> lstData = new ArrayList<Object>();
				if (type == String.class)
				{
					for (XElement e : ele.xPathSelectElements("" + v.path()))
					{
						lstData.add(e.getValue());
					}
				}
				else
				{
					for (XElement e : ele.xPathSelectElements("" + v.path()))
					{
						lstData.add(getData(e, noListInfo, type));
					}
				}

				value = lstData;
			}
			else
			{
				Class<?> type = (Class<?>) field.getGenericType();
				try
				{
					value = type.newInstance();
					if (type == String.class)
					{
						XElement e = ele.xPathSelectElement("" + v.path());
						if (e != null)
						{
							value = e.getValue();
						}
					}
					else
					{
						XElement e = ele.xPathSelectElement("" + v.path());
						if (e != null)
						{
							value = getData(e, noListInfo, type);
						}
					}
				}
				catch (Exception e)
				{
					LOGGER.error(e.getMessage());
				}
			}

			boolean access = field.isAccessible();
			try
			{
				field.setAccessible(true);
				try
				{
					field.set(result, value);
				}
				catch (Exception e)
				{
					LOGGER.error(e.getMessage());
				}

				field.setAccessible(false);
			}
			finally
			{
				if (!access) field.setAccessible(false);
			}
		}

		return (T) result;
	}

	public static XElement getElement(Object t)
	{
		return getElement(t, "", t.getClass());
	}

	public static XElement getElement(Object t, String itemName)
	{
		return getElement(t, itemName, t.getClass());
	}

	public static XElement getElement(Object t, Class<?> clazz)
	{
		return getElement(t, "", clazz);
	}

	public static XElement getElement(Object t, String itemName, Class<?> clazz)
	{
		if (clazz == null) clazz = t.getClass();
		if (StringHelper.isNullOrWhiteSpace(itemName))
		{
			XmlClass classInfo = ReflectHelper.getXmlClass(clazz);
			itemName = classInfo.AttrName();
		}
		if (!StringHelper.isNullOrWhiteSpace(itemName))
		{
			XElement result = new XElement(itemName);

			List<XmlPropertyData> lstProperties = ReflectHelper.getXmlProperties(clazz);
			for (XmlPropertyData v : lstProperties.stream().filter(x -> StringHelper.isNullOrWhiteSpace(x.path())).collect(Collectors.toList()))
			{
				result.setAttributeValue(v.attrName(), ObjectHelper.getString(ReflectHelper.getValue(t, v.attrName())));
			}

			for (XmlPropertyData v : lstProperties.stream().filter(x -> !StringHelper.isNullOrWhiteSpace(x.path())).collect(Collectors.toList()))
			{
				List<?> lst = (List<?>) ReflectHelper.getValue(t, v.propertyName());
				if (lst != null)
				{
					String[] paths = v.path().split("/");
					String nodeName = paths[paths.length - 1];
					XElement currentXElement = result;
					for (String path : paths)
					{
						if (!path.equals( nodeName)) // 最后一个节点没有意义
						{
							XElement newEle = new XElement(path);
							currentXElement.add(newEle);
							currentXElement = newEle;
						}
					}

					try
					{
						// 分string 与 object类型
						Class<?> type = null;
						Field field = ReflectHelper.getField(clazz, v.propertyName());
						Type geType = field.getGenericType();
						if (geType != null)
						{
							ParameterizedType pType = (ParameterizedType) geType;
							Type t1 = pType.getActualTypeArguments()[0];

							type = (Class<?>) t1;
						}
						else
						{
							type = field.getDeclaringClass();
						}

						if (type == String.class)
						{
							for (Object data : lst)
							{
								XElement xe = new XElement(nodeName);
								xe.setValue(ObjectHelper.getString(data));
								currentXElement.add(xe);
							}
						}
						else
						{
							for (Object data : lst)
							{
								XElement xe = getElement(data, nodeName, data.getClass());

								currentXElement.add(xe);
							}
						}
					}
					catch (Exception e)
					{
						LOGGER.error(e.getMessage());
					}
				}
			}

			return result;
		}

		return null;
	}

}
